#include "InterpolationCenter.h"
#include "Command_Agent.h"
#include "DIVA_KeyFrame.h"
#include <sstream>
#include "VMStatus.h"
#include "ScopeInvokedObj.h"
#include "PositionEvent.h"
#include "ColorEvent.h"
#include "xVMRelationStruct.h"

InterpolationCenter* InterpolationCenter::_myInstance = NULL;

InterpolationCenter* InterpolationCenter::getInstance(){
	if(_myInstance == NULL){
		_myInstance = new InterpolationCenter();
	}
	return _myInstance;
}

InterpolationCenter::InterpolationCenter(){
	_status = false;
	this->_keyFrameNum = 0;
}

void InterpolationCenter::render(float timeSinceLastFrame){
	this->_frame_time = timeSinceLastFrame;
	if(this->_keyFrameNum > 1){
		renderTargetKeyFrame(this->_keyFrameNum);//render the latest key frame
	}
}

void InterpolationCenter::disableAnimation(){
	this->setStatus(false);//set status to false
	if(this->_keyFrameNum != 0){
		DIVA_KeyFrame* currentKeyFrame = getTargetKeyFrameByKeyFrameNumber(this->_keyFrameNum);//get current key frame
		currentKeyFrame->recover();//recover VMs position or color
	}
}

void InterpolationCenter::newKeyFrame(){
	int line = Command_Agent::getInstance()->getLineNumber();//get line number
	this->_keyframeRecord[make_pair(_keyFrameNum+1,line)] = new DIVA_KeyFrame();//generates a new key frame
}

void InterpolationCenter::snapShot(){
	if(getStatus()){
		recoverVM(); // frameStarted keep change VM positions, so before we take a snapshot
		                      // we should recover all th VM to its original position, color, ...
		                      // for example, because animation is enabled, a vm is changing from 0 to 100,  recoverVM() recover 
		                      // its position to 100
		if(_keyFrameNum != 0){
			getTargetKeyFrameByKeyFrameNumber(_keyFrameNum)->exploreVM();
			//explore VMs in new keyframe
		}
		newKeyFrame();// 
		computeWOPInterpolationBetweenLastTwoKeyFrame();//在每次更新wops值時就更新keyframe資料,09/11/06 by hyt
		computeVMInterpolationBetweenLastTwoKeyFrame();
		increaseKeyFrameNumber();
	}
}

void InterpolationCenter::computeWOPInterpolationBetweenLastTwoKeyFrame(){
	int current = this->_keyFrameNum+1;
	int previous = current-1;
	if(previous >= 1 ){//不只一個keyframe
		DIVA_KeyFrame* currentKeyFrame = getTargetKeyFrameByKeyFrameNumber(current);
		DIVA_KeyFrame* previousKeyFrame = getTargetKeyFrameByKeyFrameNumber(previous);
		if(currentKeyFrame != NULL && previousKeyFrame != NULL){
			computeWOPInterpolation(previousKeyFrame,currentKeyFrame);
		}
	}
	else{
		//代表目前只有一個keyframe,do nothing
	}
}

void InterpolationCenter::computeVMInterpolationBetweenLastTwoKeyFrame(){
	int current = this->_keyFrameNum+1;
	int previous = current-1;
	if(previous >= 1 ){//不只一個keyframe
		DIVA_KeyFrame* currentKeyFrame = getTargetKeyFrameByKeyFrameNumber(current);
		DIVA_KeyFrame* previousKeyFrame = getTargetKeyFrameByKeyFrameNumber(previous);
		if(currentKeyFrame != NULL && previousKeyFrame != NULL){
			computeVMInterpolation(previousKeyFrame,currentKeyFrame);
		}
	}
	else{
		//代表目前只有一個keyframe,do nothing
	}
}


void InterpolationCenter::renderTargetKeyFrame(int targetKey){
	/*render key frame*/
	DIVA_KeyFrame* currentKeyFrame = getTargetKeyFrameByKeyFrameNumber(targetKey);
	currentKeyFrame->render(_speed*this->_frame_time/_frames);
}

void InterpolationCenter::computeWOPInterpolation(DIVA_KeyFrame* kf1, DIVA_KeyFrame* kf2){
	vector<WOPInvokedObj*> prewops = kf1->getWOPKeyFrameObjects();
	vector<WOPInvokedObj*> currentwops = kf2->getWOPKeyFrameObjects();
	/*if(currentwops.size() != prewops.size()){
		kf2->pruneWOPObjisOutOfScope(prewops);
	}*/
	generateWOPChangeEvents(prewops,currentwops);
	generateTargetWOPInterpolation(currentwops);	
}

void InterpolationCenter::computeVMInterpolation(DIVA_KeyFrame* kf1, DIVA_KeyFrame* kf2){
	VMStatusTable preVMs = kf1->getVMStatusTable();
	VMStatusTable currentVMs = kf2->getVMStatusTable();
	generateVMChangeEvents(preVMs,currentVMs);
	generateTargetVMInterpolation(kf2);
}

void InterpolationCenter::generateWOPChangeEvents(vector<WOPInvokedObj*> pre,vector<WOPInvokedObj*> current){
	vector<WOPInvokedObj*>::iterator it1,it2;
	
	for(it1 = current.begin() ; it1 != current.end() ; ++it1){
		for(it2 = pre.begin() ; it2 != pre.end() ; ++it2){
			writePastValue((*it2),(*it1));
		}
	}
}

void InterpolationCenter::writePastValue(WOPInvokedObj* pre,WOPInvokedObj* current){
	/*兩種情況, 
	1.兩個obj行數相同時,past & current value必須一致,以pre obj為準
	2.兩個obj行數不同時,將pre obj的current value寫到current obj的past value*/
	if(pre->getEntry()->getLongName() == current->getEntry()->getLongName()){
		if(pre->getLineNumber() == current->getLineNumber()){			
			current->getChangeEvent()->setPastValue(pre->getChangeEvent()->getPastValue());
			current->getChangeEvent()->setCurrentValue(pre->getChangeEvent()->getCurrentValue());
		}
		else{
			current->getChangeEvent()->setPastValue(pre->getChangeEvent()->getCurrentValue());
			//pre->recover();
		}		
	}	
}

void InterpolationCenter::generateVMChangeEvents(VMStatusTable pre,VMStatusTable current){

	/*一一比對pre key frame 以及 current key frame的LyStatus ,
	1. 若pre key frame沒有 current key frame的 VM , 此VM要產生ColorChange
	2. 若pre key frame  有 current key frame的 VM , 檢查VM的position , 
	有改變 = 產生PositionChange
	*/
	//分三部份處理 , NewlyObj , LyInvokedObj , DeletionObj , 目前DeletionObj沒處理
	DIVA_KeyFrame* currentKeyFrame = getTargetKeyFrameByKeyFrameNumber(_keyFrameNum+1);
	int line = Command_Agent::getInstance()->getLineNumber();

	vector<DIVA_VM*> newvms = getNewlyVMs(pre,current);
	vector<DIVA_VM*> deletionvms = getDeletionVMs(pre,current);
	vector<DIVA_VM*> lyvms  = getLyInvokedVMs(pre,current);
	
	/*這裡新增了所有newly object到current key frame裡
	  不過通常newly object也會牽扯到layout , 所以我會在addNewScopeInvokedObj這個method裡
	  產生一個新的LyInvokedObj*/
	vector<DIVA_VM*>::iterator it;
	for(it = newvms.begin() ; it != newvms.end() ; ++it){
		currentKeyFrame->addNewScopeInvokedObj(new ScopeInvokedObj(line,(*it)));
		vector<DIVA_VM*> childs = xVMRelationStruct::getInstance()->VMRS_nextVMsByRef((*it));
		Ogre::Vector3 currentPos = current[(*it)]->getPos();
		(*it)->setPosition(currentPos);		
		if(childs.size() != 0){//有child , 就從左上方作為起始座標
			LyInvokedObj* lyio = new LyInvokedObj(line,(*it));			
			Ogre::Vector3 prePos = currentPos+Ogre::Vector3(-100,100,0);
			PositionEvent* posEvt = new PositionEvent(prePos,currentPos);
			lyio->setChangeEvent(posEvt);
			currentKeyFrame->addNewLyInvokedObj(lyio);
		}		
	}
	for(it = deletionvms.begin() ; it != deletionvms.end() ; ++it){		
		currentKeyFrame->addNewScopeInvokedObj(new ScopeInvokedObj(line,(*it)));		
	}
	//新增所有LyInvoked object到current key frame裡
	for(it = lyvms.begin() ; it != lyvms.end() ; ++it){
		Ogre::Vector3 prePos = pre[(*it)]->getPos();
		Ogre::Vector3 currentPos = current[(*it)]->getPos();
		if(prePos != currentPos){
			LyInvokedObj* lyio = new LyInvokedObj(line,(*it));
			PositionEvent* posEvt = new PositionEvent(prePos,currentPos);
			lyio->setChangeEvent(posEvt);
			currentKeyFrame->addNewLyInvokedObj(lyio);
		}
	}
}

void InterpolationCenter::generateTargetWOPInterpolation(vector<WOPInvokedObj*> target){
	vector<WOPInvokedObj*>::iterator it;
	for(it = target.begin(); it!= target.end(); ++it){
		(*it)->generateInterpolation();
	}
}

void InterpolationCenter::generateTargetVMInterpolation(DIVA_KeyFrame* kf){
	vector<LyInvokedObj*> ly = kf->getLyKeyFrameObjects();
	vector<LyInvokedObj*>::iterator it;
	for(it = ly.begin(); it != ly.end(); ++it){
		(*it)->generateInterpolation();
	}
	vector<ScopeInvokedObj*> sio = kf->getScopeKeyFrameObjects();
	vector<ScopeInvokedObj*>::iterator itr;
	for(itr = sio.begin() ; itr != sio.end() ; ++itr){
		(*itr)->generateInterpolation();
	}
}

DIVA_KeyFrame* InterpolationCenter::getTargetKeyFrameByKeyFrameNumber(int key){
	KeyFrameRecord::iterator it;
	for(it = _keyframeRecord.begin() ; it != _keyframeRecord.end() ; ++it){
		if(key == (*it).first.first){
			return (*it).second;
		} 
	}
	return NULL;
}

vector<DIVA_KeyFrame*> InterpolationCenter::getTargetKeyFrameByLineNumber(int lineNumber){	
	vector<DIVA_KeyFrame*> result;
	KeyFrameRecord::iterator it;
	for(it = _keyframeRecord.begin() ; it != _keyframeRecord.end() ; ++it){
		if(lineNumber == (*it).first.second){
			result.push_back((*it).second);
		} 
	}
	return result;
}

DIVA_KeyFrame* InterpolationCenter::getTheLastKeyFrameInTargetLine(int lineNumber){
	/*For LyInvokedObject use*/
	KeyFrameRecord::iterator it;
	DIVA_KeyFrame* target = NULL;
	for(it = _keyframeRecord.begin() ; it != _keyframeRecord.end() ; ++it){
		if(lineNumber == (*it).first.second){
			target = (*it).second;
		}
	}
	return target;
}

void InterpolationCenter::recoverVM(){
	/*在CommandAgent的visualize  & update method呼叫 , 為了要讓LyInvokedObject or ScopeInvokedObject不再作動畫
	而且將Position,Color更新到最新的值*/
	DIVA_KeyFrame* keyframe = getTargetKeyFrameByKeyFrameNumber(_keyFrameNum);
	if(keyframe != NULL){
		keyframe->recoverVM();
	}
}

void InterpolationCenter::restartVM(){
	/*使用者按下enable按鈕後所呼叫*/

	int line = Command_Agent::getInstance()->getLineNumber();
	vector<DIVA_KeyFrame*> keyframes = getTargetKeyFrameByLineNumber(line);
	if(keyframes.size() == 0){
		return;
	}
	vector<DIVA_KeyFrame*>::iterator it;
	for(it = keyframes.begin() ; it != keyframes.end() ; ++it){
		(*it)->restartVM();
	}
}

vector<DIVA_VM*> InterpolationCenter::getNewlyVMs(VMStatusTable pre,VMStatusTable current){
	vector<DIVA_VM*> result;
	VMStatusTable::iterator it;
	for(it = current.begin() ; it != current.end() ; ++it){
		VMStatusTable::iterator itr;
		itr = pre.find((*it).first);
		if(itr == pre.end()){//the VM doesn't exist in previous key frame
			result.push_back((*it).first);
		}
		else{
			//do nothing
		}
	}
	return result;
}

vector<DIVA_VM*> InterpolationCenter::getDeletionVMs(VMStatusTable pre,VMStatusTable current){
	//作法同getNewlyVMs, 只是要把pre table的key值丟進去current查
	vector<DIVA_VM*> result;
	VMStatusTable::iterator it;
	for(it = pre.begin() ; it != pre.end() ; ++it){
		VMStatusTable::iterator itr;
		itr = current.find((*it).first);
		if(itr == current.end()){//the VM doesn't exist in previous key frame
			result.push_back((*it).first);
		}
		else{
			//do nothing
		}
	}
	return result;
}

vector<DIVA_VM*> InterpolationCenter::getLyInvokedVMs(VMStatusTable pre, VMStatusTable current){
	vector<DIVA_VM*> result;
	VMStatusTable::iterator it;
	for(it = current.begin() ; it != current.end() ; ++it){
		VMStatusTable::iterator itr;
		itr = pre.find((*it).first);
		if(itr != pre.end()){//the VM exists in previous key frame
			result.push_back((*it).first);
		}
		else{
			//do nothing
		}
	}
	return result;
}